package org.huzhp.oauth.client.shiro;


import org.apache.shiro.authz.Authorizer;
import org.apache.shiro.authz.ModularRealmAuthorizer;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.huzhp.oauth.client.Oauth2Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.DispatcherType;
import java.util.LinkedHashMap;
import java.util.Map;

@EnableConfigurationProperties(Oauth2Properties.class)
public abstract class Oauth2Config {


    @Autowired
    private Oauth2Properties oauth2Properties;


    @Bean("filterShiroFilterRegistrationBean")
    protected FilterRegistrationBean filterShiroFilterRegistrationBean() throws Exception {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR});
        filterRegistrationBean.setFilter(new DelegatingFilterProxy("shiroFilterFactoryBean"));
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }


    @Bean("oauth2Realm")
    public Oauth2Realm oauth2Realm() {
        return new Oauth2Realm(oauth2Properties);
    }


    @Bean
    public Authorizer authorizer() {
        return new ModularRealmAuthorizer();
    }


    private Map loadShiroFilterChain() {
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        filterChainDefinitionMap.put("/oauth", "oauth");
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/oauth/logout", "oauthLogout");
        filterChainDefinitionMap.put("/api/**", "anon");
        filterChainDefinitionMap.put("/open/**", "anon");
        filterChainDefinitionMap.put("/no", "anon");
        filterChainDefinitionMap.put("/noData", "anon");
        filterChainDefinitionMap.put("/unAuth", "anon");

        addExtendUrlFilter(filterChainDefinitionMap);

        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/public/**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/scripts/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");

        filterChainDefinitionMap.put("/error", "anon");
        filterChainDefinitionMap.put("/error/**", "anon");

        filterChainDefinitionMap.put("/**", "authc");
        return filterChainDefinitionMap;
    }

    protected abstract void addExtendUrlFilter(Map<String, String> filterChainDefinitionMap);

    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        chainDefinition.addPathDefinitions(loadShiroFilterChain());

        return chainDefinition;
    }


    @Bean("oauthLogout")
    public OauthLogoutFilter logoutFilter() {
        OauthLogoutFilter logoutFilter = new OauthLogoutFilter();
        logoutFilter.setRedirectUrl(oauth2Properties.getLogoutRedirectUrl() + "&");
        return logoutFilter;
    }

    @Bean("oauth")
    public Oauth2AuthenticationFilter getOAuth2AuthenticationFilter() {
        Oauth2AuthenticationFilter authenticatingFilter = new Oauth2AuthenticationFilter();
        authenticatingFilter.setLoginUrl(oauth2Properties.getLoginUrl());
        authenticatingFilter.setSuccessUrl(oauth2Properties.getSuccessUrl());
        return authenticatingFilter;
    }


}
